#ifndef _AVI_H_
#define _AVI_H_

#include <stdio.h>
#include <unistd.h>

/***
dwlFlags对应
AVIF_MUSTUSEINDEX：标明必须根据索引表来指定数据顺序     
AVIF_WASCAPTUREFILE：标明该AVI文件是用捕捉实时视频专门分配的文件   
AVIF_COPYRIGHTED：标明该AVI文件包含有版权信息  
*/
#define AVIF_HASINDEX           0x00000010        // Index at end of file?
#define AVIF_MUSTUSEINDEX       0x00000020
#define AVIF_ISINTERLEAVED      0x00000100
#define AVIF_TRUSTCKTYPE        0x00000800        // Use CKType to find key frames?
#define AVIF_WASCAPTUREFILE     0x00010000
#define AVIF_COPYRIGHTED        0x00020000

#define AVI_MAX_RIFF_SIZE       0x40000000LL
#define AVI_MASTER_INDEX_SIZE   256
#define AVI_MAX_STREAM_COUNT    100

/* index flags */
#define AVIIF_INDEX             0x10

typedef unsigned int FOURCC;
typedef unsigned short TWOCC;

#define TODWORD(ch) ((unsigned int)(unsigned char)(ch))
#define TOWORD(ch) ((unsigned short)(unsigned char)(ch))
#define mkFOURCC(ch0,ch1,ch2,ch3) \
	(TODWORD(ch0)|TODWORD(ch1)<<8|TODWORD(ch2)<<16|TODWORD(ch3)<<24)
#define mkTWOCC(ch0,ch1) (TOWORD(ch0)|TOWORD(ch1)<<8)

#define LIST_SIZE(list) (8+(list).list_size)

enum avi_stream_type
{
	AVI_STREAM_VIDEO = 1,
	AVI_STREAM_AUDIO = 2,
	AVI_STREAM_VAMIX = 3,
	AVI_STREAM_MAX
};

struct main_avi_header
{
	/**
	 * Specifies the number of microseconds between frames. This value indicates
	 * the overall timing for the file.
	 */
    unsigned int microsec_perframe;//显示每帧所需的时间ms,定义avi的显示速率
	/**
	 * Specifies the approximate maximum data rate of the file. This value
	 * indicates the number of bytes per second the system must handle to
	 * present an AVI sequence as specified by the other parameters contained in
	 * the main header and stream header chunks.
	 */
    unsigned int maxbytes_persec;//最大的数据传输率
    unsigned int paddinggranularity;//记录块的长度需为此值的倍数，通常是2048
    unsigned int flags;//avi文件的特殊属性，如是否包含索引块，音视频数据是否交叉存储
    unsigned int totalframe;//文件中的总帧数
    unsigned int initialframes;//说明在开始播放前需要多少帧
    unsigned int streams;//文件中包含的数据流种类
    unsigned int suggested_bufsize;//建议使用的缓冲区大小；通常为存储一帧图像以及同步声音所需要的数据之和
    unsigned int width;//图像宽
    unsigned int height;//图像高
    unsigned int reserved[4];//保留
};

struct avi_header_list //avi头部列表开始
{
	FOURCC avih;//四个字符avih，表示avi的头部信息
	long avih_size;//avi的头部信息的大小
	struct main_avi_header main_header;
};

struct stream_header//strh块,流头部
{
	FOURCC block;//"strh",表示流头部
	long list_size;//流头部大小

    FOURCC fcc_type;//4字节，表示数据流的种类,vids表示视频数据流，auds音频数据流
	/**
	 * H264: 'H264'
	 * PCM_ALAW: 0x0006, PCM_G726:0x0045
	 */
    FOURCC fcc_handler;//4字节，表示数据流编解码器
    unsigned int flags;//数据流属性
    unsigned short priority;//此数据流的播放优先级
    unsigned short language;//音频的语言代号
    unsigned int initialframes;//说明在开始播放前需要多少帧
	/*
	 * Used with dwRate to specify the time scale that this stream will use.
	 * Dividing dwRate by dwScale gives the number of samples per second. For
	 * video streams, this is the frame rate. For audio streams, this rate
	 * corresponds to the time needed to play nBlockAlign bytes of audio, which
	 * for PCM audio is the just the sample rate.
	 */
    unsigned int scale;//数据量，视频每帧的大小或者音频的采样大小
    unsigned int rate;//rate/scale = fps(pcm-audio-sample)
    unsigned int start;//数据流开始播放的位置，以dwscale为单位
    unsigned int length;//数据流的数据量，以dwscale为单位
    unsigned int suggested_bufsize;//建议缓冲区的大小
	/*
	 * Specifies an indicator of the quality of the data in the stream. Quality
	 * is represented as a number between 0 and 10,000. For compressed data,
	 * this typically represents the value of the quality parameter passed to
	 * the compression software. If set to –1, drivers use the default quality
	 * value.
	 */
    unsigned int quality;//解压缩质量参数，值越大，质量越好,0-10000
	/**
	 * Specifies the size of a single sample of data. This is set to zero if the
	 * samples can vary in size. If this number is nonzero, then multiple
	 * samples of data can be grouped into a single chunk within the file. If it
	 * is zero, each sample of data (such as a video frame) must be in a
	 * separate chunk. For video streams, this number is typically zero,
	 * although it can be nonzero if all video frames are the same size. For
	 * audio streams, this number should be the same as the nBlockAlign member
	 * of the WAVEFORMATEX structure describing the audio.
	 */
    unsigned int samplesize;//音频的采样大小,字节数
	struct rect 
	{
		 short int left;
		 short int top;
		 short int right;
		 short int bottom;
	} frame_rect;  // 指定这个流（视频流或文字流）在视频主窗口中的显示位置
};

struct JUNK //option 可选
{
	FOURCC list;//四个字符LIST，表示列表    
	long list_size;//列表大小，不包括list,size_list字段，小字节顺序
	char data[]; /// junk data, must to write data point memory
};

struct bitmapinfo
{
    unsigned int size;//位图信息大小,sizeof(struct_bitmapinfo)
    long width;//图像宽度
    long height;//图像高度
    unsigned short planes;//目标设备位面数，设为1
    unsigned short bit_count;//单位像素的位数，即图像的位深度
	/**
	 * For compressed video and YUV formats, this member is a FOURCC code,
	 * specified as a DWORD in little-endian order. For example, YUYV video has
	 * the FOURCC 'VYUY' or 0x56595559. For more information, see FOURCC Codes.
	 * For uncompressed RGB formats, the following values are possible:
	 * 	BI_RGB,BI_BITFIELDS.
	 */
    unsigned int compression;//图像的压缩类型
    unsigned int image_size;//图像的大小，以字节为单位
    long x_pixels;//水平方向每米像素数
    long y_pixels;//垂直方向每米像素数
    unsigned int clrused;//实际使用的颜色数目
	unsigned int clr_important;//对图像显示有重要影响的颜色索引的数目，如果是0，则都重要
};

struct wavformatex
{
	unsigned short format_tag; //编码格式
	unsigned short channels; //声道数
	unsigned int samples_persec;//采样频率
	unsigned int avgbytes_persec;//每秒数据量
	unsigned short block_align;// 块对齐
	unsigned short bits_persample;// 采用精度
	unsigned short cbsize;// 结构大小
};

struct video_stream_format//流格式块
{
	FOURCC block;//"strf"
	long block_size;
	
	struct bitmapinfo bmp_info;
};

/* flags for wFormatTag field of WAVEFORMAT */
#define WAVE_FORMAT_PCM     1
struct audio_stream_format//流格式块
{
	FOURCC block;//"strf"
	long block_size;
	
    unsigned short format_tag;        /* format type */
    unsigned short channels;         /* number of channels (i.e. mono, stereo...) */
	/*
	 * Sample rate, in samples per second (hertz). If wFormatTag is
	 * WAVE_FORMAT_PCM, then common values for nSamplesPerSec are 8.0 kHz,
	 * 11.025 kHz, 22.05 kHz, and 44.1 kHz. For non-PCM formats, this member
	 * must be computed according to the manufacturer's specification of the
	 * format tag.
	 */
    unsigned int samples_persec;    /* sample rate */
	/*
	 * Required average data-transfer rate, in bytes per second, for the format
	 * tag. If wFormatTag is WAVE_FORMAT_PCM, nAvgBytesPerSec must equal
	 * nSamplesPerSec × nBlockAlign. For non-PCM formats, this member must be
	 * computed according to the manufacturer's specification of the format tag.
	 */
    unsigned int avgbytes_persec;   /* for buffer estimation */
	/*
	 * Block alignment, in bytes. The block alignment is the minimum atomic unit
	 * of data for the wFormatTag format type. If wFormatTag is WAVE_FORMAT_PCM,
	 * nBlockAlign must equal (nChannels × wBitsPerSample) / 8. For non-PCM
	 * formats, this member must be computed according to the manufacturer's
	 * specification of the format tag.
	 */
    unsigned short block_align;       /* block size of data */
	/*
	 * Bits per sample for the wFormatTag format type. If wFormatTag is
	 * WAVE_FORMAT_PCM, then wBitsPerSample should be equal to 8 or 16. For
	 * non-PCM formats, this member must be set according to the manufacturer's
	 * specification of the format tag. If wFormatTag is WAVE_FORMAT_EXTENSIBLE,
	 * this value can be any integer multiple of 8.
	 * Some compression schemes do not define a value for wBitsPerSample, so
	 * this member can be zero.
	 */
    unsigned short bits_persample;
};
struct video_stream_header_list //avi流头部列表
{
	FOURCC list;//"list"
	long list_size;
	FOURCC list_type;//"strl"数据流类型

	struct stream_header str_header;//strh块,流头部
	struct video_stream_format str_format;//流格式块
};
struct audio_stream_header_list //avi流头部列表
{
	FOURCC list;//"list"
	long list_size;
	FOURCC list_type;//"strl"数据流类型

	struct stream_header str_header;//strh块,流头部
	struct audio_stream_format str_format;//流格式块
};
struct header_list //avi头部信息块的开始
{
	FOURCC list;//四个字符list，表示列表 
	long list_size;//列表大小，不包括list,list_size字段，小字节顺序
	FOURCC list_type;//四个字符，列表类型，如hdrl
	
	struct avi_header_list header;//avi头部列表开始
	struct video_stream_header_list video_str;//avi流头部列表
	struct audio_stream_header_list audio_str; 
};

struct media_data //一帧媒体数据的开始
{
	/** streamID + TypeCode
	 * TypeCode: 
	 * 	'db' - 非压缩视频帧
	 * 	'dc' - 压缩视频帧
	 * 	'pc' - 改用新的调色板
	 * 	'wb' - 音频帧
	 */
	FOURCC flag;//"00dc"表示视频"00wb"表示音频
	unsigned long size;//一帧视频或音频大小
	unsigned char data[];
};
struct movie_list //媒体数据整体数据的开始
{
	FOURCC list;//四个字符"LIST"
	unsigned long list_size;//整个媒体块的大小，字节数,包括"movi"
	FOURCC movi;//"movi"表示视频媒体块的开始

	struct media_data m_data; //一帧媒体数据的开始
};

/*************** AVI OLE index ***************/
#define AVIIF_LIST       0x00000001
#define AVIIF_KEYFRAME   0x00000010
#define AVIIF_NO_TIME    0x00000100
#define AVIIF_COMPRESSOR 0x0FFF0000  // unused?
struct avioldindex_enty
{
	FOURCC chunk_id;//表征本数据块的四字符码, '00dc','01wb' .etc
	unsigned int flags;//说明本数据块是不是关键帧，AVIIF_KEYFRAME
	unsigned int offset;//本数据块(include size)在文件中的偏移量,相对与list-movi起始
	unsigned int size;//本数据块的大小
};
struct avi_old_index
{
    FOURCC fcc;//必须为idx1,数字1
    unsigned int cb; //本数据结构的大小，不包括最初的8字节(fcc和cb两个域)
    struct avioldindex_enty aindex[];//这是一个数组，为每个媒体数据块定义一个索引值
}st_avi_old_index;

struct avi_file //AVI文件的开始
{
    FOURCC riff;//四个字符RIFF
    long file_size;//文件大小，不包括riff,file_size字段，小字节顺序
    FOURCC file_type;//文件类型，四个字符：AVI
    
    struct header_list header;//AVI头部信息块的开始
    struct JUNK junk;//option 可选
    struct movie_list movie;//媒体数据整体数据的开始
    struct avi_old_index tailer; /// optional item
};

//********************** External Data Structure and APIs ***************//
/** 
 * It's same with the @struct record_media_param@ in RSC ,
 * but for independency of avi-pack,we copy it here,
 * so may you need to convert record_media_param to avi_media_param
 * if you modify one structure of them.
 *
 * You should declare and complete the converted functions out of avi-pack,
 * for example, you can define it in RSC adapter layer source file.
 */
struct avi_media_param 
{
	/** video param */
	unsigned int video_cbr; /**NOT USED: cbr: 1, vbr: 0 */
	unsigned int video_bitrate; /// unit: bps
	unsigned int video_framerate;
	unsigned int video_gop; /** NOT USED */
	unsigned int video_codec; /* 1 - H264(default), 2 - MJPEG */
	unsigned int video_width;
	unsigned int video_height;
	unsigned int pic_level; /* NOT USED, picture level: 1-5, low to high */
	/** audio param */
	unsigned int audio_sample_fmt; /** bits: 8 or 16 */
	unsigned int audio_sample_rate; /* unit is HZ  */
	unsigned int audio_channels; /* perhaps value: 1,2,3 */
	unsigned int audio_bitrate;
	unsigned int audio_codec; /*1 - PCM_ALAW(FIXED), 2 - AAC */
};

typedef struct avi_handle
{
	char fname[64]; /// avi file name
	FILE *fp; /// avi file HANDLE
	unsigned long file_extra_offset; /// the size of user-extra data in the file-header
	unsigned long video_frames;/// video total frames
	unsigned long audio_frames;/// audio total frames
	unsigned long mdata_size;/// total media data size
	unsigned long riff_size_offset;/// used to update RIFF_SIZE in file
	unsigned long movie_size_offset;/// used to update MOVIE_SIZE in file
	unsigned long total_frames_offset;/// used to update total_frames in avih chunk 
	unsigned long video_frames_offset;/// used to update video_frames in strl-strh chunk 
	struct avi_file avi_ctx;
} *AVI_HANDLE;

/********* Functions **********/
/**
 * check parameters,open avi file and write avi header 
 *
 * @param[in] filename avi file name to open/created
 * @param[in] mparam video and audio parameters to pack avi file
 * @param[in] strtype stream type to pack avi file,see @enum avi_stream_type
 * @return a handle of AVI_HANDLE type if success, or NULL if failed;
 * you need pass it in the next avi api using.hanle is malloced,so must free.
 * @see avi_exit_handle
 */
AVI_HANDLE avi_init_handle(const char *filename, struct avi_media_param *mparam,int strtype);

/**
 * write a video or audio frame to avi file opened by avi_init_handle call
 *
 * @param[in] pavi a AVI_HANDLE created by avi_init_handle
 * @param[in] buf video or audio frame data buf address
 * @param[in] size frame buffer data size
 * @ret return 0 if success, or -1 if failed.
 */
int avi_write_packet(AVI_HANDLE pavi, int type, unsigned char *buf,int size);

/**
 * write avi file trailer,and free dynamic created resource
 *
 * @param[in] pavi the AVI_HANDLE created by avi_init_handle
 */
void avi_exit_handle(AVI_HANDLE pavi);

/**
 * fix damaged avi file to normal or could be played
 *
 * @param[in] filename the avi file name to be fixed
 * @ret retur 0 if success, or -1 if failed.
 */
int avi_fix_handle(const char *filename);

/**
 * check parameters,open avi file and write user-extra data and avi header 
 *
 * @param[in] filename avi file name to open/created
 * @param[in] mparam video and audio parameters to pack avi file
 * @param[in] strtype stream type to pack avi file,see @enum avi_stream_type
 * @param[in] data user extra data to put in the file header
 * @param[in] len user extra data length to put in the file header
 * @return a handle of AVI_HANDLE type if success, or NULL if failed;
 * you need pass it in the next avi api using.hanle is malloced,so must free.
 * @see avi_exit_handle
 * @note this kind file would not be fixed.
 */
AVI_HANDLE avi_init_handle_2(const char *filename, struct avi_media_param *mparam,
		int strtype,void *data,int len);

#endif

